import json
from decimal import Decimal

from django import http
from django.shortcuts import render

# Create your views here.
from django.db import transaction
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo
from apps.users.models import Address
from meiduo_mall.utils.views import LoginRequiredJSONMixin


class OrderSettlementView(LoginRequiredJSONMixin,View):
    """结算订单"""
    def put(self,request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user

        # 查询当前用户的所有地址信息
        addresses = Address.objects.filter(user=request.user,is_deleted=False)

        # 从Redis购物车中查询出被勾选的商品信息
        redis_client = get_redis_connection("carts")
        carts_data = redis_client.hgetall(user.id)
        # 格式转换
        carts_dict = []
        for key,value in carts_data.items():
            sku_id = int(key.decode())
            sku_dict = json.loads(value.decode())
            if sku_dict['selected']:
                carts_dict[sku_id] = sku_dict

        # 查询商品信息
        sku_list = []
        skus = SKU.objects.filter(id__in=carts_dict.keys())
        for sku in skus:
            sku_list.append({
                "id":sku.id,
                "name":sku.name,
                "default_image_url":sku.default_image.url,
                "count":carts_dict[sku.id]["count"],
                "price":sku.price,
            })

        # 补充运费
        freight = Decimal("10.00")

        addresses_list=[]
        for address in  addresses:
            addresses_list.append({
                "id":address.id,
                "province":address.province.name,
                "city":address.city.name,
                "district":address.district.name,
                "place":address.place,
                "receiver":address.receiver,
                "mobile":address.mobile
            })

        # 渲染界面
        context = {
            "addresses":addresses_list,
            "skus":sku_list,
            "freight":freight,
        }

        # 返回响应
        return http.JsonResponse({"code":0,"errmsg":"OK","context":context})


class OrderCommitView(View):
    """订单提交"""
    def post(self,request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get("address_id")
        pay_method = json_dict.get("pay_method")

        # 校验参数
        if not all([address_id,pay_method]):
            return http.JsonResponse({"code":400,"errmsg":"缺少必传参数"})

        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({"code":400,"errmsg":"参数address_id错误"})
        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM["CASH"],OrderInfo.PAY_METHODS_ENUM["ALIPAY"]]:
            return http.JsonResponse({"code":400,"errmsg":"参数pay_method错误"})

        # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime("%Y%m%d%H%M%S") + ('%09d' % user.id)

        # --------设置事物起始--------
        with transaction.atomic():
            # --------事物保存点--------
            save_id = transaction.savepoint()
            try:
                # 保存订单基本信息 OrderInfo
                order = OrderInfo.objects.create(
                    order_id = order_id,
                    user = user,
                    address = address,
                    total_count = 0,
                    total_amount = Decimal("0"),
                    freight = Decimal("10.00"),
                    pay_method = pay_method,
                    status = OrderInfo.ORDER_STATUS_ENUM["UNPAID"],
                )

                # 从 redis 读取购物车中被勾选的商品信息
                redis_client = get_redis_connection("cats")
                carts_data = redis_client.hgetall(user.id)

                # 转换格式
                carts_dict = {}
                for key,value in carts_data.items():
                    sku_id = int(key.decode())
                    sku_dict = json.loads(value.decode())
                    if sku_dict['selected']:
                        carts_dict[sku_id] = sku_dict

                # 获取选中的商品id:
                sku_ids = carts_dict.keys()

                # 遍历购物车中被勾选的商品信息
                for sku_id in sku_ids:
                    while True:
                        # 查询 SKU 信息
                        sku = SKU.objects.get(id=sku_id)

                        # 原始销量 和  库存量
                        origin_sales = sku.sales
                        origin_stock = sku.stock

                        # 判断 SKU 库存
                        sku_count = carts_dict[sku_id]['count']
                        if sku_count > sku.stock:
                            return http.JsonResponse({"code":400,"errmsg":"库存不足"})

                        # SKU减少库存，增加销量
                        sku.stock -= sku_count
                        sku.sales += sku_count
                        sku.save()

                        # 使用乐观锁 更新库存量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
                                                                                          sales=new_sales)

                        # 修改SPU销量
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        # 保存订单商品信息 OrderGoods
                        OrderInfo.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        # 保存商品订单中总价和总数量
                        order.total_count += sku_count
                        order.total_amount += (sku_count * sku.price)
                        break

                # 添加邮费和保存订单信息
                order.total_amount += order.freight
                order.save()
            except:
                # --------事物回滚--------
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({"code":400,"errmsg":"下单失败"})

            # --------提交事物--------
            transaction.savepoint_commit(save_id)

        # 清除购物车中已结算的商品
        redis_client.hdel(user.id,*carts_dict)

        # 响应提交订单结果
        return http.JsonResponse({"code":0,"errmsg":"OK","order_id":order.order_id})


